package com.siyu.model.dispatch.utils;

import com.alibaba.fastjson.JSONObject;
import com.siyu.model.dispatch.io.*;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 本类主要包含全局通用的方法，为全局工具类
 *
 * @author xinchan
 * @version 1.0.1 2022-04-23
 */
public class CommonUtils {
    /**
     * 按预定格式生成 JSON 对象，包含三个部分：head, dataList, KEYS
     *
     * @return
     */
    public static JSONObject createJSONObject(List<JSONObject> dataList) {
        JSONObject jsonObject = new JSONObject(new LinkedHashMap<>());
        jsonObject.put("head", getHead());
        jsonObject.put("dataList", dataList);
        jsonObject.put("showKeys", getKEYS());

        return jsonObject;
    }

    public static List<String> getKEYS() {
        final String[] strs = {
                "OBJECT", "NM", "CSLEVEL", "RKPEAK", "RKPEAKTIME", "MAXLEVEL", "MAXLEVELTIME", "MEXSD", "OVERSTDTIME",
                "MEXLM", "OVERLIMITTIME", "CKPEAK", "CKPEAKTIME", "RKVOLUME", "CKVOLUME", "ENDLEVEL", "EEXLM"
        };
        return Arrays.asList(strs);
    }

    public static List<JSONObject> getHead() {
        List<JSONObject> list = new ArrayList<>();
        JSONObject jsonObject = new JSONObject(new LinkedHashMap<>());
        jsonObject.put("OBJECT", "对象");
        jsonObject.put("NM", "名称");
        jsonObject.put("CSLEVEL", "初始水位");
        jsonObject.put("RKPEAK", "入库洪峰流量");
        jsonObject.put("RKPEAKTIME", "入库峰现时间");
        jsonObject.put("MAXLEVEL", "最高水位");
        jsonObject.put("MAXLEVELTIME", "最高水位出现时间");
        jsonObject.put("MEXSD", "最高水位是否超标准");
        jsonObject.put("OVERSTDTIME", "超标准水位时段");
        jsonObject.put("MEXLM", "最高水位是否超汛限");
        jsonObject.put("OVERLIMITTIME", "超讯限水位时段");
        jsonObject.put("CKPEAK", "出库洪峰");
        jsonObject.put("CKPEAKTIME", "出库峰现时间");
        jsonObject.put("RKVOLUME", "入库洪量");
        jsonObject.put("CKVOLUME", "出库洪量");
        jsonObject.put("ENDLEVEL", "调度期末水位");
        jsonObject.put("EEXLM", "末水位是否超汛限");
        list.add(jsonObject);
        return list;
    }

    /**
     * 将属性值转换为 JSON 格式
     *
     * @param input
     * @param output
     */
    public static JSONObject addJSONObject(SingleDamInput input, SingleDamOutput output) {
        JSONObject jsonObject = new JSONObject(new LinkedHashMap<>());
        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        jsonObject.put("OBJECT", "水库");
        jsonObject.put("NM", input.getReservoirName());
        jsonObject.put("CSLEVEL", decimalFormat.format(output.getInitialLevel()));
        jsonObject.put("RKPEAK", decimalFormat.format(output.getFloodPeak()));
        jsonObject.put("RKPEAKTIME", output.getRKPeakTime());
        jsonObject.put("MAXLEVEL", decimalFormat.format(output.getMaxLevel()));
        jsonObject.put("MAXLEVELTIME", output.getMaxLevelTime());
        jsonObject.put("MEXSD", output.getMaxLevelExceedStandard());
        jsonObject.put("OVERSTDTIME", output.getOverStandardTime());
        jsonObject.put("MEXLM", output.getMaxLevelExceedLimit());
        jsonObject.put("OVERLIMITTIME", output.getOverLimitTime());
        jsonObject.put("CKPEAK", decimalFormat.format(output.getFloodDischarge()));
        jsonObject.put("CKPEAKTIME", output.getCKPeakTime());
        jsonObject.put("RKVOLUME", decimalFormat.format(output.getFloodVolume()));
        jsonObject.put("CKVOLUME", decimalFormat.format(output.getCKVolume()));
        jsonObject.put("ENDLEVEL", decimalFormat.format(output.getEndLevel()));
        jsonObject.put("EEXLM", output.getEndLevelExceedLimit());
        return jsonObject;
    }

    public static JSONObject addJSONObject(String startTime, List<Double> tempQ, String name) throws ParseException {
        JSONObject jsonObject = new JSONObject(new LinkedHashMap<>());
        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        jsonObject.put("OBJECT", "流域出口");
        jsonObject.put("NM", name.split("-")[0]);
        double downLevelFromLQInChukou = CalculateUtils.getDownLevelFromLQInChukou(tempQ.get(0), name);
        jsonObject.put("CSLEVEL", decimalFormat.format(downLevelFromLQInChukou));
        jsonObject.put("RKPEAK", decimalFormat.format(Collections.max(tempQ)));
        int timeSpan = tempQ.indexOf(Collections.max(tempQ));
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = simpleDateFormat.parse(startTime);
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        instance.add(Calendar.HOUR, timeSpan);
        Date date1 = instance.getTime();
        jsonObject.put("RKPEAKTIME", simpleDateFormat.format(date1));
        double maxLevel = CalculateUtils.getDownLevelFromLQInChukou(Collections.max(tempQ), name);
        jsonObject.put("MAXLEVEL", decimalFormat.format(maxLevel));
        jsonObject.put("MAXLEVELTIME", simpleDateFormat.format(date1));

        double normalLevel;
        if (name.equals("yagang-liuxihe")) {
            normalLevel = 3.2;
        } else if (name.equals("yagang-bainihe")) {
            normalLevel = 6;
        } else if (name.equals("dasheng-zengjiang")) {
            normalLevel = 8;
        } else if (name.equals("dasheng-xifuhe")) {
            normalLevel = 3.8;
        } else {
            normalLevel = -1;
        }
        jsonObject.put("MEXSD", maxLevel > normalLevel ? "是" : "否");

        String overStandard = CalculateUtils.overWaterLevel(getOptimalLineLevel(tempQ, name), normalLevel, startTime);
        jsonObject.put("OVERSTDTIME", overStandard);
        jsonObject.put("MEXLM", "--");
        jsonObject.put("OVERLIMITTIME", "--");
        jsonObject.put("CKPEAK", "--");
        jsonObject.put("CKPEAKTIME", "--");
        double sum = tempQ.stream().mapToDouble(x -> x).sum() * 3600 / 100000000;
        jsonObject.put("RKVOLUME", decimalFormat.format(sum));
        jsonObject.put("CKVOLUME", "--");
        jsonObject.put("ENDLEVEL", decimalFormat.format(CalculateUtils.getDownLevelFromLQInChukou(tempQ.get(tempQ.size() - 1), name)));
        jsonObject.put("EEXLM", "--");
        return jsonObject;
    }

    public static JSONObject addJSONObject(SingleSluiceInput input, SingleSluiceOutput output) {
        JSONObject jsonObject = new JSONObject(new LinkedHashMap<>());
        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        jsonObject.put("OBJECT", "闸坝");
        jsonObject.put("NM", input.getSluiceName());
        List<Double> list = input.getOperationRunoffData();
        double initialLevel = CalculateUtils.getDownLevelFromLQInSluiceInput(list.get(0), input.getSluiceName());
        jsonObject.put("CSLEVEL", decimalFormat.format(initialLevel));
        jsonObject.put("RKPEAK", decimalFormat.format(output.getFloodPeak()));
        jsonObject.put("RKPEAKTIME", output.getRKPeakTime());
        jsonObject.put("MAXLEVEL", decimalFormat.format(output.getMaxLevel()));
        jsonObject.put("MAXLEVELTIME", output.getMaxLevelTime());
        jsonObject.put("MEXSD", output.getMaxLevelExceedStandard());
        jsonObject.put("OVERSTDTIME", output.getOverStandardTime());
        jsonObject.put("MEXLM", output.getMaxLevelExceedLimit());
        jsonObject.put("OVERLIMITTIME", output.getOverLimitTime());
        jsonObject.put("CKPEAK", decimalFormat.format(output.getFloodDischarge()));
        jsonObject.put("CKPEAKTIME", output.getCKPeakTime());
        jsonObject.put("RKVOLUME", decimalFormat.format(output.getFloodVolume()));
        jsonObject.put("CKVOLUME", decimalFormat.format(output.getCKVolume()));
        double endLevel = CalculateUtils.getDownLevelFromLQInSluiceInput(list.get(list.size() - 1), input.getSluiceName());
        jsonObject.put("ENDLEVEL", decimalFormat.format(endLevel));
        jsonObject.put("EEXLM", output.getEndLevelExceedLimit());
        return jsonObject;
    }

    /**
     * TODO: 考虑实现水库和闸坝的超类，便于使用多态，代码更简洁
     * 将 SingleDamOutput 和 SingleSluiceOutput 中的公共属性转换为 JSON 格式
     *
     * @param jsonObject
     */
    private static void addJSONFromOutput(JSONObject jsonObject) {
        return;
    }

    /**
     * 获取 List 元素之和
     *
     * @param list
     * @return
     */
    public static double getSumValue(List<Double> list) {
        return list.stream().mapToDouble(x -> x).sum();
    }

    /**
     * 生成增江水库、闸坝调度调令(优化调度)、输出到文档，后面可以不要
     *
     * @param output        输出类 FloodDispatchOutput
     * @param folderPath    文件目录
     * @param reservoirName 流域名称
     * @throws IOException
     */
    public static void createSchedulingSuggestions2Txt(FloodDispatchOutput output, String folderPath, String reservoirName) throws IOException {
        // 输出到文档，后面可以不要
//        String path = folderPath + File.separator + "SchedulingSuggestions.txt";
//        StringBuilder oneLine = new StringBuilder();
//        ArrayList<String> list = new ArrayList<>();
//        int size = output.getSluiceList().size();
//
//        oneLine.append("DetailedSchedulingSuggestions: \n");
//        for (int i = 0; i < size; i++) {
//            oneLine.append(output.getSluiceList().get(i).getDetailedSchedulingSuggestions()).append("\n");
//        }
//        list.add(oneLine.append("\n").toString());
//        oneLine.delete(0, oneLine.length());  // 清空 StringBuilder 对象 oneLine
//
//        oneLine.append("SimpleSchedulingSuggestions: \n");
//        for (int i = 0; i < size; i++) {
//            oneLine.append(output.getSluiceList().get(i).getSimpleSchedulingSuggestions()).append("\n");
//        }
//        list.add(oneLine.append("\n").toString());
//        oneLine.delete(0, oneLine.length());  // 清空 StringBuilder 对象 oneLine
//
//        oneLine.append("WaterLevelComparisonResult: \n");
//        for (int i = 0; i < size; i++) {
//            oneLine.append(output.getSluiceList().get(i).getWaterLevelComparisonResult()).append("\n");
//        }
//        list.add(oneLine.append("\n").toString());
//        oneLine.delete(0, oneLine.length());  // 清空 StringBuilder 对象 oneLine
//
//        oneLine.append("CollectSuggestion: \n");
//        //oneLine.append(reservoirName).append("水库、闸坝调度调令(优化调度)\n");
//        oneLine.append(output.getCollectSuggestion()).append("\n");
//        list.add(oneLine.append("\n").toString());
//
//        File file1 = new File(path);
//        FileUtils.writeLines(file1, "UTF-8", list);
    }

    /**
     * 根据流量列表 tempQ 计算水位
     *
     * @param tempQ
     * @return
     */
    public static List<Double> getOptimalLineLevel(List<Double> tempQ, String name) {
        List<Double> level = new ArrayList<>();
        for (Double q : tempQ) {
            level.add(CalculateUtils.getDownLevelFromLQInChukou(q, name));
        }
        return level;
    }
}
